/*
 * author      : 吴中勤 
 * date        : 2018/11/11
 * description : TODO
 */

package org.wzq.learn.port.provide;

//import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.wzq.learn.domain.member.MemberEO;
import org.wzq.learn.port.consume.shop.ShopDTO;
import org.wzq.learn.port.consume.shop.ShopClient;
import org.wzq.learn.domain.member.MemberRepository;
import org.wzq.learn.infrastructure.lib.trace.CustomThreadContext;
import org.wzq.learn.infrastructure.lib.trace.threadpool.CustomThreadPool;

import java.util.List;
import java.util.concurrent.Future;

@RefreshScope
@RestController
public class TradeController {

    private static final Logger logger = LoggerFactory.getLogger(TradeController.class);

//    @Primary
//    @Bean
//    public Sampler alwaysSampler() {
//        return Sampler.ALWAYS_SAMPLE;
//    }

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @Autowired
    private ShopClient shopClient;

    @Autowired
    private CustomThreadPool customThreadPool;

    // ms-foo-dev.properties
    // profile: dev-1.0.1
    @Value("${spring.datasource.name}")
    private String cfgFromConfigCenter;

    @RequestMapping(value = "/ruok")
    public String ruok() {
        return "imok";
    }

    @RequestMapping(value = "/wrong")
    public String wrong() {
        throw new RuntimeException("wrong");
    }

    @RequestMapping(value = "/wrong3")
    public String wrong3() {
        throw new IllegalArgumentException("wrong3");
    }

    @RequestMapping(value = "/wrong2")
    public String wrong2() {
        if (logger.isInfoEnabled()) logger.info("TradeController, threadId=" + Thread.currentThread().getId());

        customThreadPool.executor(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (logger.isInfoEnabled()) logger.info("in thread, appRuntimeEnv = " + CustomThreadContext.show());
            // 测试异常会被捕获, 并发送到 sentry
            throw new RuntimeException("wrong here");
        });

        return "wrong";
    }

    @RequestMapping(value = "/thread")
    public String thread() {
        if (logger.isInfoEnabled()) logger.info("TradeController, threadId=" + Thread.currentThread().getId());
        customThreadPool.executor(() -> {
            if (logger.isInfoEnabled()) logger.info("in thread, CustomThreadContext=" + CustomThreadContext.show());
            try {
                Thread.sleep(5 * 1000);
                shopClient.listShops();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (logger.isInfoEnabled()) logger.info("thread done");
        });
        return "thread";
    }

    @RequestMapping(value = "/thread2")
    public String thread2() throws Exception {
        Future<List<ShopDTO>> shops = customThreadPool.submit(() -> shopClient.listShops());
        while (shops.isDone()) {
            Thread.sleep(100);
        }
        if (logger.isInfoEnabled()) logger.info("shops size=" + shops.get().size());

        return "thread2";
    }

    // @HystrixCommand(fallbackMethod = "listShopFallback")
    @RequestMapping(value = "/shops")
    public List<ShopDTO> listShop() {
        if (logger.isInfoEnabled()) logger.info("TradeController, threadId=" + Thread.currentThread().getId());
        return shopClient.listShops();
    }

    // private List<ShopDTO> listShopFallback() {
    //     List<ShopDTO> shopList = new ArrayList<>(1);
    //     shopList.add(new ShopDTO("mockId", "mockName", "mockSellerId"));
    //     return shopList;
    // }

    @RequestMapping(method = RequestMethod.POST, value = "/shops/{shopId}", consumes = "application/json")
    public ShopDTO updateShop(@PathVariable("shopId") String shopId, @RequestBody ShopDTO shopDTO) {
        if (logger.isInfoEnabled()) logger.info("updateShop, shopId={}, shopDTO={}", shopId, shopDTO);
        return shopClient.update(shopId, shopDTO);
    }

    @RequestMapping(value = {"/shop-ruok", "/hi-shop"}, method = RequestMethod.GET)
    public String hello(String name) {
        return restTemplate.getForObject("http://shop-service/shop/ruok?name=" + name, String.class);
    }

    @RequestMapping(value = {"/hi2"}, method = RequestMethod.GET)
    public String hello2(String name) {
        ServiceInstance serviceInstance = loadBalancerClient.choose("shop-service");
        if (null == serviceInstance) {
            return "not found";
        }

        String info = serviceInstance.getServiceId() + ":" +
                serviceInstance.getHost() + ":" +
                serviceInstance.getPort();
        logger.info(info);
        return info;
    }


    @RequestMapping(value = {"/hi3"}, method = RequestMethod.GET)
    public String cfgFromConfigCenter() {
        return cfgFromConfigCenter;
    }


    @Autowired
    private MemberRepository memberRepository;

    @RequestMapping(value = {"/member-add"}, method = RequestMethod.GET)
    public MemberEO addMember() {
        MemberEO m = new MemberEO();
        m.setName("foo");
        m.setSex("male");
        return memberRepository.addMember(m);
    }

    @RequestMapping(value = {"/member/{id}"}, method = RequestMethod.GET)
    public MemberEO findMember(@PathVariable Integer id) {
        return memberRepository.findById(id);
    }

}
